
package com.zcp.pcsuitall;

import android.content.Context;
import android.util.Log;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 对外通讯接口，主要用来负责通讯。
 */
public class Communition extends Thread {

    private int port = 8849;

    private String localIp = "127.0.0.1";

    private Context context = null;

    private SocketChannel ssc;
    
    private String cipherKey="";

    private Object lock = new Object();

    public Communition(String ip, int port, Context context,String cipherKey) {
        localIp = ip;
        this.port = port;
        this.context = context;
        this.cipherKey=cipherKey;
    }

    public void setCipherKey(String cipherKey)
    {
        this.cipherKey=cipherKey;
    }
    
    /**
     * 线程启动初始化socket，并且开始监听。
     */
    public void run() {
        try {
            Selector s = initializeSelector();
            while (true) {
                int n = s.select();
                if (n == 0) {// 没有指定的I/O事件发生
                    continue;
                }
                Iterator<SelectionKey> it = s.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    it.remove();
                    if (key.isAcceptable()) {// 侦听端信号触发
                        // 启动一个新的连接
                        acceptNewCon(key, s);
                    } else {
                        // 处理数据
                        dealWithData(key,context);
                    }
                }
            }
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
    }



    /**
     * 接收客户端数据。
     * 
     * @param sc 连接通道。
     * @return
     */
    public static void receiveData(SelectionKey key, Context context,String cipherKey) {
        BusinessControl.dealWithBusiness(key, context,cipherKey);
    }

    
    public void closeSocketChannel(SelectionKey key) {
        synchronized (lock) {
//        SuitUtil.sendConnectionStatusMes(context,false);
        if(key!=null)
        {
            try {     
                key.cancel();
                key.channel().close();
            } catch (IOException e) {                
                e.printStackTrace();
            }
        }
        }
    }
    /**
     * 向客户端发送数据。<br>
     * 
     * @param sc 通道，必须支持可写。<br>
     * @param value 要发送的数据。<br>
     */
    public boolean sendData(SocketChannel sc, String value) {
        synchronized (lock) {
            boolean result = false;
            if (ssc == null) {
                return result;
            }
            try {
                byte[] valueByte = value.getBytes();
                ByteBuffer w_buff = ByteBuffer.allocate(valueByte.length);
                w_buff.clear();
                w_buff.put(valueByte);
                w_buff.flip();
                EchoToClient(sc, w_buff);
                w_buff.clear();
                valueByte = null;
                w_buff = null;
                result = true;
            } catch (IOException ioe) {
                ioe.printStackTrace();
                Log.e(TAG, ioe.getMessage());
            }
            return result;

        }
    }

    /**
     * 向客户端发送数据。<br>
     * *
     * 
     * @param sc 通道，必须支持可写。<br>
     * @param value 要发送的数据。<br>
     */
    public boolean sendData(String value) {
        return sendData(ssc, value);
    }

    /**
     * 初始化选择监听器。<br>
     * 
     * @return
     * @throws IOException
     */
    private Selector initializeSelector() throws IOException {
        // 生成一个侦听端
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 将侦听端设为异步方式
        ssc.configureBlocking(false);
        // 生成一个信号监视器
        Selector s = Selector.open();
        // 侦听端绑定到一个端口
        ssc.socket().bind(new InetSocketAddress(localIp, port));
        // 设置侦听端所选的异步信号OP_ACCEPT
        ssc.register(s, SelectionKey.OP_ACCEPT);

        return s;
    }    

    /**
     * 接受一个新的连接。
     * 
     * @param key
     * @param s
     * @throws IOException
     */
    private void acceptNewCon(SelectionKey key, Selector s) throws IOException {
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        // 接受一个新的连接
        SocketChannel sc = server.accept();
        sc.configureBlocking(false);
        // 设置该socket的异步信号OP_READ:当socket可读时，
        sc.register(s, SelectionKey.OP_READ);

        ssc = sc;// 由于只有当个客户端连接，所以就保留一个。
        SuitUtil.sendConnectionStatusMes(context,true);
    }
    

    /**
     * 当数据可读的时候就接收数据，并处理相应的结果。
     * 
     * @param key
     */
    private void dealWithData(SelectionKey key,Context context) {
        try {
            if (key.isReadable()) {// 某socket可读信号
                receiveData(key, context,cipherKey);
            }
        } catch (Exception e) {
            Log.e(TAG, "dealWithData  " + e.getMessage());
            closeSocketChannel(key);
        }
    }

    /**
     * 发送数据到通道客户端中。<br>
     * 
     * @param sc
     * @param write_buff
     * @throws IOException
     */
    private void EchoToClient(SocketChannel sc, ByteBuffer write_buff) throws IOException {
        while (write_buff.hasRemaining()) {
            sc.write(write_buff);
        }
    }

    private static String TAG = "Communition";

}
